package cn.billho.popcache.starter.aop;

import cn.billho.popcache.annotation.CacheClear;
import cn.billho.popcache.core.api.ICacheApi;
import cn.billho.popcache.core.key.IKeyGenerate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;

/**
 * 清除缓存
 */
@Aspect
@Service
@Slf4j
public class PopCacheClearAspect {
    @Autowired
    ICacheApi cacheApi;

    @Autowired
    IKeyGenerate keyGenerate;

    @Pointcut("@annotation(cn.billho.popcache.annotation.CacheClear)")
    public void aspect() {
    }

    @Pointcut("@annotation(cn.billho.popcache.annotation.CacheClear.List)")
    public void aspectList() {
    }

    @Around("aspect()&&@annotation(anno)")
    public Object interceptor(ProceedingJoinPoint invocation, CacheClear anno)
            throws Throwable {
        Object result = invocation.proceed();
        try{
            clearCache(invocation, anno);
        }
        catch (Exception ex){
            log.warn(ex.getMessage(),ex);
        }
        return result;
    }

    @Around("aspectList()&&@annotation(annos)")
    public Object interceptor(ProceedingJoinPoint invocation, CacheClear.List annos)
            throws Throwable {
        Object result = invocation.proceed();
        try{
            for (CacheClear anno :
                    annos.value()) {
                clearCache(invocation, anno);
            }
        }
        catch (Exception ex){
            log.warn(ex.getMessage(),ex);
        }
        return result;
    }

    private void clearCache(ProceedingJoinPoint invocation, CacheClear anno) throws InstantiationException, IllegalAccessException {
        MethodSignature signature = (MethodSignature) invocation.getSignature();
        Method method = signature.getMethod();
        Class<?>[] parameterTypes = method.getParameterTypes();
        Object[] arguments = invocation.getArgs();
        String region = "";
        String key = "";

        try {
            region = StringUtils.isBlank(anno.region()) ? null : keyGenerate.buildKey(anno.region(), parameterTypes, arguments);
            key = StringUtils.isBlank(anno.key()) ? null : keyGenerate.buildKey(anno.key(), parameterTypes, arguments);

            if (StringUtils.isBlank(region)){
                // region is blank

                if (StringUtils.isBlank(key)){
                    // reion is blank and key is blank;
                    return;
                }
                else{
                    // key is not blank;
                    cacheApi.removeKey(key);
                }

            }
            else{
                // region is not blank
                if (StringUtils.isBlank(key)){
                    // key is blank;
                    cacheApi.removeRegions(region);
                }
                else{
                    // key is not blank;
                    cacheApi.removeByRegionKey(region, key);
                }

            }
        }
        catch (Exception ex){
            log.error( ex.getMessage(), ex);
        }
    }
}
